package top.v5it.japi.ddd.tool;

import cn.hutool.core.util.StrUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhanpu
 * @date 2023/4/11
 */
public class TableToXmlTemplate {

    static String voPackageName = "top.v5it.japi.ddd.example.account.entity";

    public static void main(String[] args) throws IOException, TemplateException {
        String url = "jdbc:mysql://10.173.234.101:3306/hoft-platform";
        String user = "root";
        String password = "3wax#EDC1014";
        String outputDir = "/home/bruce/test";

        // Create Freemarker configuration
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        cfg.setClassForTemplateLoading(TableToXmlTemplate.class, "/");

        // Create data model for the template
        Map<String, Object> dataModel = new HashMap<>();
        List<Map<String, Object>> vos = null;

        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            vos = getTables(conn.getMetaData(), "hoft-platform", "root", "tb\\_%");
        } catch (Exception e) {
            e.printStackTrace();
        }

        dataModel.put("vos", vos);

        // Get the template
        Template template = cfg.getTemplate("vObj-template.xml.ftl");

        // Create output directory if it doesn't exist yet
        File outputDirFile = new File(outputDir);
        outputDirFile.mkdirs();

        // Generate the XML file using the template and data model
        FileWriter writer = new FileWriter(new File(outputDirFile, "vObj.xml"));
        template.process(dataModel, writer);
        writer.close();
    }

    /**
     * 获取表信息
     *
     * @param metaData
     * @param catalog
     * @param schemaPattern
     * @param tableNamePattern
     * @return
     */
    public static List<Map<String, Object>> getTables(DatabaseMetaData metaData, String catalog, String schemaPattern, String tableNamePattern) {
        final List<Map<String, Object>> vos = new ArrayList<>();

        try (final ResultSet tables = metaData.getTables(catalog, schemaPattern, tableNamePattern, new String[]{"TABLE"})) {
            while (tables.next()) {
                final Map<String, Object> vo = new HashMap<>();
                final String tableName = tables.getString("TABLE_NAME");
                final String name = StrUtil.removePrefix(tableName, "tb_");
                final String className = toCamelCase(name, true);
                final List<Map<String, Object>> mapList = getTableColumns(metaData, catalog, schemaPattern, tableName);

                vo.put("voPackageName", voPackageName);
                vo.put("tableName", tableName);
                vo.put("className", className);
                vo.put("properties", mapList);

                vos.add(vo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return vos;
    }

    /**
     * 获取表列信息
     *
     * @param metaData
     * @param catalog
     * @param schemaPattern
     * @param tableNamePattern
     * @return
     */
    private static List<Map<String, Object>> getTableColumns(DatabaseMetaData metaData, String catalog, String schemaPattern, String tableNamePattern) {
        final List<Map<String, Object>> properties = new ArrayList<>();

        try (final ResultSet columns = metaData.getColumns(catalog, schemaPattern, tableNamePattern, null)) {
            while (columns.next()) {
                final Map<String, Object> property = new HashMap<>();
                final String columnName = columns.getString("COLUMN_NAME");
                final String propertyName = toCamelCase(columnName, false);
                boolean isPrimaryKey = columns.getBoolean("IS_AUTOINCREMENT");

                property.put("name", propertyName);
                property.put("column", columnName);
                property.put("isPrimaryKey", isPrimaryKey);

                properties.add(property);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return properties;
    }

    /**
     * 格式转换，下划线转换驼峰式
     *
     * @param str
     * @param capitalizeFirstLetter 是否首字母大写
     * @return
     */
    private static String toCamelCase(String str, boolean capitalizeFirstLetter) {
        StringBuilder sb = new StringBuilder();
        boolean shouldCapitalize = capitalizeFirstLetter;
        for (char c : str.toCharArray()) {
            if (c == '_') {
                shouldCapitalize = true;
            } else {
                sb.append(shouldCapitalize ? Character.toUpperCase(c) : c);
                shouldCapitalize = false;
            }
        }
        return sb.toString();
    }
}
